/*
Do a client check every 60 minutes that can alert if there are any news on the client market, we also need a frame with 
5 columns, Client, latest checked version, lastest known version, fail/sucess and comments...

***

affeccted profiles box
option to turn this off...

*/
#include "stdinc.h"
#include "DCPlusPlus.h"
#include "SimpleXML.h"
#include "ClientVersionManager.h"
#include "RegexpHandler.h"
#include "LogManager.h"


//Timer manager stuff

void ClientVersionManager::on(TimerManagerListener::Minute, u_int32_t /*aTick*/) {
	if(!BOOLSETTING(USE_VERSION_CHECKER)){ return; }
	minutes++;
	
// DanShUK 28/01/06
	//Run the procedure every 60min
	//int i = 60; //int i = SETTING(CHECK_INTERVAL)
	int i = 60 * 12; // Once every 12 hours
// Could be changed, but hourly is too frequent; the web server is getting too busy. 
// Besides clients aren't updated that often :)
// End DanShUK
	if(minutes >= i){
		if(minutes >= i+4){
			downloadActive = false;
		}
		minutes = 0;
		checkList.clear();
		for(ClientVersion::Iter i = clientVersions.begin(); i != clientVersions.end(); ++i) {
			ClientVersion& cp = *i;
				checkList.push_back(cp.getAddress());
		}
	}

	//Run when client is added to the list
	if(!checkList.empty()){
		fire(VersionManagerListener::MAKE_NEW_CONNECTION, "");
	}
}

void ClientVersionManager::on(VersionManagerListener::Types type, const string& aAddy) throw() {
	if(type == MAKE_NEW_CONNECTION){
		if(!aAddy.empty()){
			checkList.push_back(aAddy);
		}
		if(checkList.empty()) { 
			//List is empty after checking a client
			saveClientList();
			fire(VersionManagerListener::LIST_UPDATED);
			return; 
		}
		
		if(downloadFile(checkList.begin()->c_str())){
			checkList.erase(checkList.begin());
		}
	}
}
//Http connection stuff
void ClientVersionManager::on(HttpConnectionListener::Data, HttpConnection* /*conn*/, const u_int8_t* buf, int len) throw() {
	downBuf.append((char*)buf, len);
}
void ClientVersionManager::on(HttpConnectionListener::Complete, HttpConnection* /*conn*/, const string& aLine) throw() {
			try {		
				c.removeListener(this);
				downloadActive = false;
				//We got some info, lest check it out
				if(!downBuf.empty() && aLine.find("http://") != string::npos && aLine.find(".xml") != string::npos) {
					// pothead starts svn191
					string version = "", message = "", url = "", version2 = "", version3 = "";
					// need to filter out Actual and Subversion for Xml reading.
					if (downBuf.find("<Version>") != string::npos && downBuf.find("</Version>") != string::npos)
						version = getThisString(downBuf, "<Version>", "</Version>", 9);
					if (downBuf.find("<VersionString>") != string::npos && downBuf.find("</VersionString>") != string::npos)
						version = getThisString(downBuf, "<VersionString>", "</VersionString>", 15);
					if (downBuf.find("<ProfileVersion>") != string::npos && downBuf.find("</ProfileVersion>") != string::npos)
						version = getThisString(downBuf, "<ProfileVersion>", "</ProfileVersion>", 16);
					if (downBuf.find("<OmegaV>") != string::npos && downBuf.find("</OmegaV>") != string::npos) 
						message = getThisString(downBuf, "<OmegaV>", "</OmegaV>", 8); 
					if (downBuf.find("<VersionVert>") != string::npos && downBuf.find("</VersionVert>") != string::npos)
						version = getThisString(downBuf, "<VersionVert>", "</VersionVert>", 13);
					if (downBuf.find("<VersionBleu>") != string::npos && downBuf.find("</VersionBleu>") != string::npos)
						version2 = getThisString(downBuf, "<VersionBleu>", "</VersionBleu>", 13);
					if (downBuf.find("<VersionJaune>") != string::npos && downBuf.find("</VersionJaune>") != string::npos)
						version3 = getThisString(downBuf, "<VersionJaune>", "</VersionJaune>", 14);
					if (downBuf.find("<Info>") != string::npos && downBuf.find("</Info>") != string::npos)
						message = getThisString(downBuf, "<Info>", "</Info>", 6);
					if (downBuf.find("<Message>") != string::npos && downBuf.find("</Message>") != string::npos)
						message = getThisString(downBuf, "<Message>", "</Message>", 9);
					if (downBuf.find("<ProfileMessage>") != string::npos && downBuf.find("</ProfileMessage>") != string::npos)
						message = getThisString(downBuf, "<ProfileMessage>", "</ProfileMessage>", 16);
					if (downBuf.find("<URL>") != string::npos && downBuf.find("</URL>") != string::npos)
						url = getThisString(downBuf, "<URL>", "</URL>", 5);
					if (downBuf.find("<Link>") != string::npos && downBuf.find("</Link>") != string::npos)
						url = getThisString(downBuf, "<Link>", "</Link>", 6);
					if (downBuf.find("<ProfileUrl>") != string::npos && downBuf.find("</ProfileUrl>") != string::npos)
						url = getThisString(downBuf, "<ProfileUrl>", "</ProfileUrl>", 12);

					if (version == "") {
						SimpleXML xml;
						xml.fromXML(downBuf);
						if (xml.findChild("Update")) {
							xml.stepIn();
							}
						xml.resetCurrentChild();
						if(xml.findChild("Version")) {
							if (xml.getChildAttrib("ActualVersion") != "" && xml.getChildAttrib("SubVersion") != "") {
								version = xml.getChildAttrib("ActualVersion") + " " + xml.getChildAttrib("SubVersion");
							}
						}
					}
					setVersion(version, message, url, aLine, version2, version3);
					// pothead ends
				}
			} catch(const Exception& e) {
					dcdebug("ClientVersionManager, reading xml: %s\n", e.getError().c_str());
			}

	downBuf = Util::emptyString;
	
	//Start checking the next client
	fire(VersionManagerListener::MAKE_NEW_CONNECTION, "");
	return;
}
void ClientVersionManager::on(HttpConnectionListener::Failed, HttpConnection* /*conn*/, const string&/* aLine*/) throw() {
		c.removeListener(this);
		downloadActive = false;
		//Damn, we failed, lets take action..
		//	setVersion("N/A", "", "", aLine, "");

	downBuf = Util::emptyString;
	
	//Start checking the next client
	fire(VersionManagerListener::MAKE_NEW_CONNECTION, "");
	return;
}

void ClientVersionManager::setVersion(const string& aVersion, const string& aMessage, const string& aURL, const string& aLine, const string& aVersion2, const string& aVersion3){
	Lock l(cs);
	for(ClientVersion::Iter i = clientVersions.begin(); i != clientVersions.end(); ++i) {
		ClientVersion& cp = *i;
		// fix for Zion
		string threeClientsOneProfileBah;
		if ( cp.getClientName() == "Zion Bleu" || cp.getClientName() == "Zion Blue" )
			threeClientsOneProfileBah = aVersion2;
		else if ( cp.getClientName() == "Zion Jaune" || cp.getClientName() == "Zion Jaune" )
			threeClientsOneProfileBah = aVersion3;
		else
			threeClientsOneProfileBah = aVersion;
		//If the new version doesnt match the old version, add a last version...
		if(aLine.find(cp.getAddress()) != string::npos || ((cp.getAddress() == "http://virus27.free.fr/zion++/version_jaune.xml" || cp.getAddress() == "http://virus27.free.fr/zion++/version_bleu.xml" || cp.getAddress() == "http://virus27.free.fr/zion++/version_vert.xml") && (aLine.find("http://virus27.free.fr/zion++.xml") != string::npos))) {
			if(!aURL.empty()) {
				cp.setClientAddress(aURL);
			}
			cp.setComment(aMessage);
			cp.setUpdateTime(Util::formatTime("%Y-%d-%m %H:%M:%S", GET_TIME()));
			if(cp.getCurrentVersion().compare(threeClientsOneProfileBah)!= 0){
				if(!cp.getCurrentVersion().empty()){
					cp.setLastVersion(cp.getCurrentVersion());
					cp.setUpdated(true);
				}
			}

			//Sulan start svn124
			if(cp.getAlert()&& cp.getUpdated()&& BOOLSETTING(ALERT_ON_CLIENT_UPDATES)){
			//End
				fire(VersionManagerListener::CLIENT_UPDATED, cp.getClientName(), threeClientsOneProfileBah, cp.getClientAddress(), aMessage);
			}
			cp.setCurrentVersion(threeClientsOneProfileBah);
		}
	}
}

//XML management
void ClientVersionManager::saveClientList() {
	try {
		SimpleXML xml;
		xml.addTag("Profiles");
		xml.stepIn();

		xml.addTag("Clients");
		xml.stepIn();
		for(ClientVersion::Iter l = clientVersions.begin(); l != clientVersions.end(); ++l) {
			xml.addTag("ClientProfile");
			xml.stepIn();
			xml.addTag("ClientName", l->getClientName());
			xml.addTag("LastVersion", l->getLastVersion());
			xml.addTag("CurrentVersion", l->getCurrentVersion());
			xml.addTag("Comment", l->getComment());
			xml.addTag("Address", l->getAddress());
			xml.addTag("ClientAddress", l->getClientAddress());
			xml.addTag("UpdateTime", l->getUpdateTime());
			xml.addTag("Alert", Util::toString(l->getAlert()));
			xml.addTag("Updated", Util::toString(l->getUpdated()));
			
			xml.stepOut();
		}
		xml.stepOut();

		xml.stepOut();

		string fname = Util::getAppPath() + "XML\\ClientVersions.xml";

		File f(fname + ".tmp", File::WRITE, File::CREATE | File::TRUNCATE);
		f.write(SimpleXML::w1252Header);
		f.write(xml.toXML());
		f.close();
		File::deleteFile(fname);
		File::renameFile(fname + ".tmp", fname);

	} catch(const Exception& e) {
		dcdebug("HubManager::saveClientList: %s\n", e.getError().c_str());
	}
}
void ClientVersionManager::loadClientList() {
	try {
		SimpleXML xml;
		xml.fromXML(File(Util::getAppPath() + "XML\\ClientVersions.xml", File::READ, File::OPEN).read());
		
		if(xml.findChild("Profiles")) {
			xml.stepIn();
			loadClientList(&xml);
			xml.stepOut();
		}
	} catch(const Exception& e) {
		dcdebug("HubManager::loadClientList: %s\n", e.getError().c_str());
	}
}
void ClientVersionManager::loadClientList(SimpleXML* aXml) {
	StringList sl, fl;

	aXml->resetCurrentChild();
	if(aXml->findChild("Clients")) {
		aXml->stepIn();
		while(aXml->findChild("ClientProfile")) {
			aXml->stepIn();
			if(aXml->findChild("ClientName"))				{ sl.push_back(aXml->getChildData()); }	else { sl.push_back(Util::emptyString); }
			if(aXml->findChild("LastVersion"))				{ sl.push_back(aXml->getChildData()); }	else { sl.push_back(Util::emptyString); }
			if(aXml->findChild("CurrentVersion"))			{ sl.push_back(aXml->getChildData()); }	else { sl.push_back(Util::emptyString); }
			if(aXml->findChild("Comment"))					{ sl.push_back(aXml->getChildData()); }	else { sl.push_back(Util::emptyString); }
			if(aXml->findChild("Address"))					{ sl.push_back(aXml->getChildData()); }	else { sl.push_back(Util::emptyString); }
			if(aXml->findChild("ClientAddress"))			{ sl.push_back(aXml->getChildData()); }	else { sl.push_back(Util::emptyString); }
			if(aXml->findChild("UpdateTime"))				{ sl.push_back(aXml->getChildData()); }	else { sl.push_back(Util::emptyString); }
			if(aXml->findChild("Alert"))					{ sl.push_back(aXml->getChildData()); }	else { sl.push_back(Util::emptyString); }
			if(aXml->findChild("Updated"))					{ sl.push_back(aXml->getChildData()); }	else { sl.push_back(Util::emptyString); }
			addClientVersion(sl[0], sl[1], sl[2], sl[3], sl[4], sl[5], sl[6], Util::toInt(sl[7]), Util::toInt(sl[8]));

			sl.clear();
			aXml->stepOut();
		}
		aXml->stepOut();
	}
}

// pothead starts svn191
string ClientVersionManager::getThisString(string input, string startText, string endText, int startSize) {
	int foundStart = 0;
	string answer = "";
	for(int j = 0; j < static_cast<int>(input.size()); j++) {
		if ((foundStart == 0) && ((j - startSize) > 0)) {
			if (input.substr(j - startSize, startSize) == startText) {
				foundStart = j;
			}
		} else if ((foundStart != 0) && ((j - foundStart - startSize + 1) > 0)) {
			if (input.substr(j - startSize + 1, startSize + 1) == endText) {
				answer = input.substr(foundStart, j - foundStart - startSize + 1);
			}
		}
	}
	return answer;
}
// pothead ends
/**
 * @file
 * $Id: ClientVersionManager.cpp 330 2005-09-01 17:52:15Z Pothead $
 */
